
let gosnConversation = OsnConversation()

class OsnConversation {
    
//    static let getInstance = OsnConversation()
    
    func getNewestMessage(_ id:Int64) ->String {
        if let message = dbMessage.getMessageInfo(id) {
            return getNewestMessage(message)
        }
        return "[unkonwn]"
    }
    func getNewestMessage(_ m:DMCCMessage) ->String {
        if(m.msgType == OsnMessageContentType.text){
            return (m.content as? OsnTextMessageContent ?? OsnTextMessageContent()).data
        }else if(m.msgType == OsnMessageContentType.card){
            return "[名片] \((m.content as! OsnCardMessageContent).name)"
        }else if(m.msgType == OsnMessageContentType.redPacket){
            return "[红包]"
        }else if(m.msgType == OsnMessageContentType.call){
            return "[呼叫]"
        }else if(m.msgType == OsnMessageContentType.file){
            return "[文件]"
        }else if(m.msgType == OsnMessageContentType.image){
            return "[图片]"
        }else if(m.msgType == OsnMessageContentType.voice){
            return "[语音]"
        }else if(m.msgType == OsnMessageContentType.video){
            return "[视频]"
        }else if(m.msgType == OsnMessageContentType.sticker){
            return "[动图]"
        }else if(m.msgType == OsnMessageContentType.unknown){
            return "[unkonwn]"
        }
        return ""
    }
    func getConversationInfo(_ osnId:String) ->DMCCConversation? {
        return dbConversation.getConversationInfo(osnId)
    }
    
    func getConversationInfoDefault(_ osnId:String) ->DMCCConversation {
        if let cs = getConversationInfo(osnId){
            return cs
        }
        let cs = DMCCConversation()
        cs.targetId = osnId
        cs.type = .Single
        return cs
    }
    func setConversationInfo(_ info:DMCCConversation) -> Bool {
        return dbConversation.addConversationInfo(info)
    }
    func getConversationType(_ osnId:String) ->OsnConversationType {
        if (osnId.hasPrefix("OSNG")) {
            return OsnConversationType.Group
        } else if (osnId.hasPrefix("OSNU")) {
            return OsnConversationType.Single
        } else if (osnId.hasPrefix("OSNS")) {
            return OsnConversationType.Service
        } else if (osnId.hasPrefix("OSNN")){
            return OsnConversationType.Notify
        }
        return OsnConversationType.Single
    }
    
    func initParam(_ osnId:String) -> DMCCConversation {
        if let cs = getConversationInfo(osnId){
            return cs
        }
        let cs = DMCCConversation()
        cs.type = getConversationType(osnId)
        cs.targetId = osnId
        cs.timestamp = OsnUtils.getTimeStamp()
        _ = dbConversation.addConversationInfo(cs)
        return cs
    }
    
    func newConversation(_ type:OsnConversationType, _ osnId:String) -> DMCCConversation {
        let cs = DMCCConversation()
        cs.type = type
        cs.targetId = osnId
        cs.timestamp = OsnUtils.getTimeStamp()
        _ = dbConversation.addConversationInfo(cs)
        return cs
    }
    func deleteConversation(_ osnId:String) ->Bool {
        return dbConversation.delConversationInfo(osnId)
    }
    func clearConversation(_ osnId:String){
        if let cs = getConversationInfo(osnId){
            cs.draft = ""
            cs.newestMessage = ""
            cs.lastMessage = 0
            cs.unread = 0
            cs.unreadMention = 0
            cs.unreadMentionAll = 0
            cs.timestamp = 0
            _ = setConversationInfo(cs)
        }
    }
    func sortConversationList(_ conversationLists: inout [DMCCConversation]) {
        conversationLists.sort {
            if $0.isTop || $1.isTop && $0.isTop != $1.isTop {return $0.isTop}
            return $0.timestamp > $1.timestamp
        }
    }
    
    func getUnread() -> Int {
        let conversations = dbConversation.listConversationInfo(-1, Int.max)
        var count = 0
        for cs in conversations {
            count += cs.unread
        }
        return count
    }
    
    func getConversationList(sorted:Bool=true) ->[DMCCConversation]{
        let conversations = dbConversation.listConversationInfo(-1, Int.max)
        var conversationLists:[DMCCConversation] = []
        let csNotify = DMCCConversation()
        var hasNotify = false
        for cs in conversations {
            if(cs.type == OsnConversationType.Service){
                hasNotify = true
                if(cs.timestamp > csNotify.timestamp){
                    csNotify.timestamp = cs.timestamp
                    csNotify.lastMessage = cs.lastMessage
                    csNotify.newestMessage = cs.newestMessage
                }
                csNotify.unread += cs.unread
            }else{
                conversationLists.append(cs)
            }
        }
        if(hasNotify){
            csNotify.targetId = "OSNN"
            csNotify.type = OsnConversationType.Notify
            conversationLists.append(csNotify)
        }
        if(sorted){
            sortConversationList(&conversationLists)
        }
        return conversationLists
    }
    func getConversationList(_ type:OsnConversationType) ->[DMCCConversation]{
        return dbConversation.listConversationInfo(type)
    }
    func getNotifyList(sorted:Bool=true) -> [DMCCConversation]{
        let conversations = dbConversation.listConversationInfo(-1, Int.max)
        var conversationLists:[DMCCConversation] = []
        for cs in conversations {
            if(cs.type == OsnConversationType.Service){
                conversationLists.append(cs)
            }
        }
        if(sorted){
            sortConversationList(&conversationLists)
        }
        return conversationLists
    }
    func updateConversationTimestamp(_ osnId:String, _ timestamp:Int64){
        if let cs = getConversationInfo(osnId) {
            if(timestamp > cs.timestamp){
                cs.timestamp = timestamp
                _ = setConversationInfo(cs)
            }
        }
    }
    func updateConversationForMessage(_ message:DMCCMessage) {
        let osnId = message.target
        var cs = getConversationInfo(osnId)
        if(cs == nil){
            let type = getConversationType(osnId)
            cs = newConversation(type, osnId)
            if(type == OsnConversationType.Single){
                if gosnUser.getUserInfo(osnId) == nil {
                    Task {await gosnUser.fetchUserInfo(osnId)}
                }
            }else if(type == OsnConversationType.Group){
                if gosnGroup.getGroupInfo(osnId) == nil {
                    Task {await gosnGroup.fetchGroupInfo(osnId)}
                }
            }else if(type == OsnConversationType.Service){
                if gosnDapp.getDappInfo(osnId) == nil {
                    Task { await gosnDapp.fetchDappInfo(osnId) }
                }
            }
        }
        if(message.direction == OsnMessageDirection.Receive){
            cs!.unread += 1
        }
        cs!.lastMessage = Int(message.id)
        cs!.timestamp = message.timestamp
        cs!.newestMessage = getNewestMessage(message)
        _ = setConversationInfo(cs!)
    }
    func clearUnread(_ osnId:String){
        if let cs = getConversationInfo(osnId){
            cs.unread = 0
            _ = setConversationInfo(cs)
        }
    }
    func saveDraft(_ osnId:String, _ text:String){
        if let cs = getConversationInfo(osnId){
            cs.draft = text
            _ = setConversationInfo(cs)
        }
    }
    func setTop(_ osnId:String, _ top:Bool){
        if let cs = getConversationInfo(osnId){
            cs.isTop = top
            _ = setConversationInfo(cs)
        }
    }
    func setSilent(_ osnId:String, _ silent:Bool){
        if let cs = getConversationInfo(osnId) {
            cs.isSilent = silent
            _ = setConversationInfo(cs)
        }
    }
}

